﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System;

namespace Utility.DataStructure
{
	public class SerializableDictionary<TKey, TValue> : IDictionary<TKey, TValue>, ISerializationCallbackReceiver
	{
		[SerializeField] TKey[] keys;
		[SerializeField] TValue[] values;
		Dictionary<TKey, TValue> dict = new Dictionary<TKey, TValue> ();

		#region Dictionary 
		public TValue this[TKey key] { get => ((IDictionary<TKey, TValue>)dict)[key]; set => ((IDictionary<TKey, TValue>)dict)[key] = value; }

		public ICollection<TKey> Keys => ((IDictionary<TKey, TValue>)dict).Keys;

		public ICollection<TValue> Values => ((IDictionary<TKey, TValue>)dict).Values;

		public int Count => ((IDictionary<TKey, TValue>)dict).Count;

		public bool IsReadOnly => ((IDictionary<TKey, TValue>)dict).IsReadOnly;

		public void Add (TKey key, TValue value)
		{
			((IDictionary<TKey, TValue>)dict).Add (key, value);
		}

		public void Add (KeyValuePair<TKey, TValue> item)
		{
			((IDictionary<TKey, TValue>)dict).Add (item);
		}

		public void Clear ()
		{
			((IDictionary<TKey, TValue>)dict).Clear ();
		}

		public bool Contains (KeyValuePair<TKey, TValue> item)
		{
			return ((IDictionary<TKey, TValue>)dict).Contains (item);
		}

		public bool ContainsKey (TKey key)
		{
			return ((IDictionary<TKey, TValue>)dict).ContainsKey (key);
		}

		public void CopyTo (KeyValuePair<TKey, TValue>[] array, int arrayIndex)
		{
			((IDictionary<TKey, TValue>)dict).CopyTo (array, arrayIndex);
		}

		public IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator ()
		{
			return ((IDictionary<TKey, TValue>)dict).GetEnumerator ();
		}

		public bool Remove (TKey key)
		{
			return ((IDictionary<TKey, TValue>)dict).Remove (key);
		}

		public bool Remove (KeyValuePair<TKey, TValue> item)
		{
			return ((IDictionary<TKey, TValue>)dict).Remove (item);
		}

		public bool TryGetValue (TKey key, out TValue value)
		{
			return ((IDictionary<TKey, TValue>)dict).TryGetValue (key, out value);
		}

		IEnumerator IEnumerable.GetEnumerator ()
		{
			return ((IDictionary<TKey, TValue>)dict).GetEnumerator ();
		}
		#endregion
		#region serialization
		void ISerializationCallbackReceiver.OnAfterDeserialize ()
		{
			if (dict == null)
			{
				dict = new Dictionary<TKey, TValue> ();
			}
			else
			{
				dict.Clear ();
			}
			for (int i = 0; i < keys.Length; i++)
			{
				dict.Add (keys[i], values[i]);
			}
			keys = null;
			values = null;
		}

		void ISerializationCallbackReceiver.OnBeforeSerialize ()
		{
			keys = dict.Keys.ToArray ();
			values = dict.Values.ToArray ();
		}
		#endregion


	}

	#region frenquently used types
	[Serializable] public class StringIntDict : SerializableDictionary<string, int> { }
	[Serializable] public class StringFloatDict : SerializableDictionary<string, float> { }
	[Serializable] public class StringBoolDict : SerializableDictionary<string, bool> { }
	[Serializable] public class StringStringDict : SerializableDictionary<string, string> { }
	[Serializable] public class StringObjectDict : SerializableDictionary<string, UnityEngine.Object> { }

	#endregion
}